//package com.yc.mygatewayfilterfactory;
//
//import com.alibaba.cloud.commons.lang.StringUtils;
//import com.google.gson.Gson;
//import com.yc.utils.JwtTokenUtil;
//import io.jsonwebtoken.*;
//import io.jsonwebtoken.io.Decoders;
//import io.jsonwebtoken.security.Keys;
//import lombok.Data;
//import lombok.extern.java.Log;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.boot.context.properties.ConfigurationProperties;
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
//import org.springframework.cloud.gateway.filter.GlobalFilter;
//import org.springframework.core.Ordered;
//import org.springframework.core.io.buffer.DataBuffer;
//import org.springframework.http.HttpStatus;
//import org.springframework.http.server.reactive.ServerHttpRequest;
//import org.springframework.http.server.reactive.ServerHttpResponse;
//import org.springframework.stereotype.Component;
//import org.springframework.util.AntPathMatcher;
//import org.springframework.web.server.ServerWebExchange;
//import reactor.core.publisher.Flux;
//import reactor.core.publisher.Mono;
//
//import java.security.Key;
//import java.util.*;

/**
 * @program: cloud147
 * @description:  全局认证过滤器
 * @author: zy
 * @create: 2025-07-16 17:12
 */
//@Component
//@Log
//public class GlobalAuthFilter  implements GlobalFilter, Ordered {
////    @Value("${tokens.secrets}")
//    @Value("${token.secret}")
//    private  String secret;
//
//    // 注入我们新创建的配置属性类
//    private final AppProperties appProperties;
//    private final JwtTokenUtil jwtTokenUtil;
//
//    // AntPathMatcher 用于路径匹配，支持通配符
//    private final AntPathMatcher pathMatcher = new AntPathMatcher();
//
//    // 通过构造器注入 AppProperties
//    public GlobalAuthFilter(AppProperties appProperties, JwtTokenUtil jwtTokenUtil) {
//        this.appProperties = appProperties;
//        this.jwtTokenUtil = jwtTokenUtil;
//    }
//
//    @Override
//    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        ServerHttpRequest request=exchange.getRequest();
//
//        // 获取请求路径
//        String path = request.getURI().getPath();
//        log.info("Request path: " + path);
//        //检查path是否是rights中的一个路径，如果是，则要进行下面的token认证，都不是则直接放行
//        boolean shouldCheckToken=false;
//        for( String excludePath : appProperties.getExcludePaths() ){
//            if( pathMatcher.match(excludePath, path) ){
//                shouldCheckToken=true;
//                break;
//            }
//        }
//        if( !shouldCheckToken ){
//            return chain.filter( exchange );
//        }
//
//        ServerHttpResponse response=exchange.getResponse();
//        String token=request.getHeaders().getFirst("token");
//        if( StringUtils.isEmpty( token )) {
//            Map<String,Object> map=new HashMap(){
//                //语法糖
//                {
//                    put("code",0);
//                    put("msg","没有登录");
//                }
//            };
//            return response( response, map);
//        }else{
//            //解析token, 校验token的时间有效性
//            if(    !isTokenValidate(  token ) ){
//                Map<String,Object> map=new HashMap(){
//                    {
//                        put("code",0);
//                        put("msg","token无效");
//                    }
//
//                };
//                return response( response, map);
//            }else{
//
//                //满足条件，放行请求，自定义请求头
//                String userId = String.valueOf(jwtTokenUtil.extractUserId(token));
////                String userId = String.valueOf(jwtTokenUtil.extractUserId(token));
//                Set<String> roleset = jwtTokenUtil.extractRoles(token);
//                // 使用 StringJoiner
//                StringJoiner joiner = new StringJoiner(",");
//                roleset.forEach(joiner::add);
//                String roles = joiner.toString();
//                //自定义请求头来转发请求
//                ServerHttpRequest modifiedRequest = request.mutate()
//                        .header("X-User-ID", userId)
//                        .header("X-User-Roles", roles)
//                        .build();
//
//
////                return  chain.filter( exchange);  //放行请求
//                // 替换请求并放行
//                return chain.filter(exchange.mutate().request(modifiedRequest).build());
//            }
//        }
//    }
//
//    private boolean isTokenValidate(String token) {
//        try {
//            Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
//
//            Jws<Claims> claimsJws = Jwts.parserBuilder()
//                    .setSigningKey(key)
//                    .build()
//                    .parseClaimsJws(token);
//
//            Claims claims = claimsJws.getBody();
//            Date expiration = claims.getExpiration();
//            Date now = new Date();
//
//            if (expiration != null && expiration.before(now)) {
//                return false;
//            } else {
//                log.info("Token 有效");
//                log.info("用户名: " + claims.get("name"));
//                log.info("过期时间: " + expiration);
//                log.info("产生日间: " + claims.get("iat"));
//                return true;
//            }
//        } catch (ExpiredJwtException e) {
//            log.severe("Token 已过期！");
//        } catch (JwtException e) {
//            e.printStackTrace();
//            log.severe("Token 非法！");
//        }
//        return false;
//    }
//
//    //出错的情况 下的响应
//    private Mono<Void> response(ServerHttpResponse response, Object msg){
//        response.getHeaders().add("Content-Type","application/json;charset=utf-8");
//        //String resJson= JSONUtil.toJsonPrettyStr(   msg );
//        Gson g=new Gson();
//        String resjson=g.toJson(   msg );
//        DataBuffer dataBuffer=response.bufferFactory().wrap( resjson.getBytes() );
//        return response.writeWith( Flux.just(dataBuffer ) );  //响应json数据
//    }
//
//    @Override
//    public int getOrder() {
//        return Ordered.HIGHEST_PRECEDENCE;
//    }
//}
//
//
//@Component // 将此配置类声明为组件，使其能够被Spring扫描并管理
//@ConfigurationProperties(prefix = "rights")  //自动配置 自动注入application.yml中的rights列表
//@Data // 使用 Lombok 的 @Data 自动生成 getter 和 setter
//class AppProperties {
//    private List<String> excludePaths; // 对应 application.yml 中的 rights 列表
//}

package com.yc.mygatewayfilterfactory;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.google.gson.Gson;
import com.yc.utils.JwtTokenUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.Data;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.security.Key;
import java.util.*;

@Component
@Log
public class GlobalAuthFilter implements GlobalFilter, Ordered {
    @Value("${token.secret}")
    private String secret;

    private final AppProperties appProperties;
    private final JwtTokenUtil jwtTokenUtil;
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    public GlobalAuthFilter(AppProperties appProperties, JwtTokenUtil jwtTokenUtil) {
        this.appProperties = appProperties;
        this.jwtTokenUtil = jwtTokenUtil;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 获取请求路径
        String path = request.getURI().getPath();
        log.info("请求路径: " + path);

        // 检查是否是白名单路径
        if (isExcludedPath(path)) {
            log.info("路径在白名单中，直接放行");
            return chain.filter(exchange);
        }

        // 检查token
        String token = request.getHeaders().getFirst("token");
        if (StringUtils.isEmpty(token)) {
            log.warning("请求头中没有找到token");
            return unauthorizedResponse(response, "请先登录系统");
        }

        try {
            // 验证token有效性
            if (!isTokenValidate(token)) {
                log.warning("token验证失败");
                return unauthorizedResponse(response, "登录已过期，请重新登录");
            }

            // 提取用户信息并添加到请求头
            String userId = String.valueOf(jwtTokenUtil.extractUserId(token));
            Set<String> roleset = jwtTokenUtil.extractRoles(token);
            String roles = String.join(",", roleset);

            log.info("用户ID: " + userId + ", 角色: " + roles);

            ServerHttpRequest modifiedRequest = request.mutate()
                    .header("X-User-ID", userId)
                    .header("X-User-Roles", roles)
                    .build();

            return chain.filter(exchange.mutate().request(modifiedRequest).build());

        } catch (ExpiredJwtException e) {
            log.severe("Token已过期: " + e.getMessage());
            return unauthorizedResponse(response, "登录已过期，请重新登录");
        } catch (JwtException e) {
            log.severe("Token无效: " + e.getMessage());
            return unauthorizedResponse(response, "无效的登录凭证");
        } catch (Exception e) {
            log.severe("系统错误: " + e.getMessage());
            return errorResponse(response, "系统错误，请稍后再试");
        }
    }

    private boolean isExcludedPath(String path) {
        for (String excludePath : appProperties.getExcludePaths()) {
            if (pathMatcher.match(excludePath, path)) {
                return false; // 返回false表示需要认证
            }
        }
        return true; // 返回true表示不需要认证
    }

    private boolean isTokenValidate(String token) {
        try {
            Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
            Jws<Claims> claimsJws = Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token);

            Claims claims = claimsJws.getBody();
            Date expiration = claims.getExpiration();
            Date now = new Date();

            if (expiration != null && expiration.before(now)) {
                return false;
            }
            return true;
        } catch (JwtException e) {
            throw e; // 抛出异常让上层处理
        }
    }

    private Mono<Void> unauthorizedResponse(ServerHttpResponse response, String message) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return errorResponse(response, message);
    }

    private Mono<Void> errorResponse(ServerHttpResponse response, String message) {
        response.getHeaders().add("Content-Type", "application/json;charset=utf-8");
        Map<String, Object> map = new HashMap<>();
        map.put("code", HttpStatus.UNAUTHORIZED.value());
        map.put("msg", message);
        map.put("success", false);

        Gson gson = new Gson();
        String json = gson.toJson(map);
        DataBuffer buffer = response.bufferFactory().wrap(json.getBytes());
        return response.writeWith(Flux.just(buffer));
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

@Component
@ConfigurationProperties(prefix = "rights")
@Data
class AppProperties {
    private List<String> excludePaths;
}
